package com.karson.service.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.karson.common.config.rabbitmq.MsgProducer;
import com.karson.common.config.rabbitmq.RabbitConfig;
import com.karson.common.config.redis.RedisConfig;
import com.karson.common.constants.BusinessConstants;
import com.karson.common.constants.Constants;
import com.karson.common.dto.rabbitmq.TagStatusMessageDTO;
import com.karson.common.exception.AsmrException;
import com.karson.common.model.*;
import com.karson.common.request.TagRequest;
import com.karson.common.request.UserActionRequest;
import com.karson.common.response.TagResponse;
import com.karson.common.util.RedisUtil;
import com.karson.service.dao.TagInfoMapper;
import com.karson.service.service.ActionCountsService;
import com.karson.service.service.AlbumTagsService;
import com.karson.service.service.TagInfoService;
import com.karson.service.service.UserActionService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author ZKS
 */
@Service
public class TagInfoServiceImpl extends ServiceImpl<TagInfoMapper, TagInfo> implements TagInfoService {
    @Autowired
    private TagInfoMapper tagInfoMapper;
    @Autowired
    private AlbumTagsService albumTagsService;
    @Autowired
    private ActionCountsService actionCountsService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserActionService userActionService;
    @Autowired
    private MsgProducer msgProducer;
    @Override
    public IPage<TagResponse> pageList(IPage<TagResponse> tagInfoPage) {
        return tagInfoMapper.pageList(tagInfoPage);
    }

    @Override
    public boolean update(TagRequest request) {
        try {
            TagInfo tagInfo = new TagInfo();
            BeanUtils.copyProperties(request, tagInfo);
            updateById(tagInfo);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    @Override
    public TagResponse getTagStat(Integer albumId, Integer tagId) {
        TagInfo tagInfo = super.getById(tagId);
        if (tagInfo == null) {
            return null;
        }
        TagResponse tagResponse = BeanUtil.copyProperties(tagInfo, TagResponse.class);
        String key = RedisConfig.TAG_COUNT_KEY +  tagId + ":" + albumId;
        String hashLikeKey = RedisConfig.HASH_LIKE_KEY;
        String hashDislikeKey = RedisConfig.HASH_DISLIKE_KEY;

        // 如果有key存在就说明有人点赞过，没有直接返回0
        Map<Object, Object> countMap  = redisUtil.hmGetAll(key);
        Integer likes;
        Integer disLikes;

        Object likesObj = countMap.get(hashLikeKey);
        Object disLikesObj = countMap.get(hashDislikeKey);

        if (likesObj == null || disLikesObj == null) {
            // 说明缓存没命中，从数据库查询
            LambdaQueryWrapper<ArAlbumTag> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ArAlbumTag::getAlbumId, albumId);
            queryWrapper.eq(ArAlbumTag::getTagId, tagId);
            ArAlbumTag albumTag = albumTagsService.getOne(queryWrapper);
            if (albumTag != null) {
                likes = albumTag.getAgreeCount();
                disLikes = albumTag.getDisagreeCount();
                if (likesObj == null){
                    redisUtil.hmSet(key,hashLikeKey,likes);
                }else {
                    redisUtil.hmSet(key,hashDislikeKey,disLikes);
                }
            } else {
                likes = 0;
                disLikes = 0;
                // 种回redis
                redisUtil.hmSet(key,hashLikeKey,likes);
                redisUtil.hmSet(key,hashDislikeKey,disLikes);
            }
        } else {
            likes = Integer.parseInt(likesObj.toString());
            disLikes = Integer.parseInt(disLikesObj.toString());
        }
        tagResponse.setTagGreat(likes);
        tagResponse.setTagLess(disLikes);
        // 判断是否点赞或踩
        Object userId = StpUtil.getLoginId();
        String v = tagId + ":" + albumId;
        boolean liked = redisUtil.sIsMember(RedisConfig.ALBUM_USER_LIKE + userId,v);
        boolean disLiked = redisUtil.sIsMember(RedisConfig.ALBUM_USER_DISLIKE + userId, v);
        tagResponse.setIsLike(liked);
        tagResponse.setIsDisLike(disLiked);
        return tagResponse;
    }

    @Override
    public void changeTagStat(Integer albumId, Integer tagId, String type) {
        // 改变标签点赞状态
        LambdaQueryWrapper<ArAlbumTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArAlbumTag::getAlbumId,albumId);
        queryWrapper.eq(ArAlbumTag::getTagId,tagId);
        ArAlbumTag albumTag = albumTagsService.getOne(queryWrapper);
        if (albumTag == null) {
            throw new AsmrException("找不到该标签");
        }
        String key = RedisConfig.COUNT_KEY + BusinessConstants.BUSINESS_TAG +":" + tagId + ":" + albumId;
        String userSetKey;
        String actionHashKey;
        String oppositeSetKey = null;
        String oppositeHashKey = null;
        int userId = StpUtil.getLoginIdAsInt();
        switch (type) {
            case Constants.ACTION_GREAT -> {
                actionHashKey = RedisConfig.HASH_LIKE_KEY;
                userSetKey = RedisConfig.ALBUM_USER_LIKE;
                oppositeHashKey = RedisConfig.HASH_DISLIKE_KEY;
                oppositeSetKey = RedisConfig.ALBUM_USER_DISLIKE;
            }
            case Constants.ACTION_LESS -> {
                actionHashKey = RedisConfig.HASH_DISLIKE_KEY;
                userSetKey = RedisConfig.ALBUM_USER_DISLIKE;
                oppositeHashKey = RedisConfig.HASH_LIKE_KEY;
                oppositeSetKey = RedisConfig.ALBUM_USER_LIKE;
            }
            default -> {
                return; // 未知操作类型直接返回
            }
        }
        boolean hasAction = redisUtil.sIsMember(userSetKey + userId, tagId + ":" + albumId);
        boolean hasOpposite = redisUtil.sIsMember(oppositeSetKey + userId, tagId + ":" + albumId);
        if (hasAction) {
            // 已操作 -> 取消
            redisUtil.hincrBy(key, actionHashKey, -1);
            redisUtil.removeMember(userSetKey + userId, tagId + ":" + albumId);
        } else {
            // 新增操作
            redisUtil.hincrBy(key, actionHashKey, 1);
            redisUtil.add(userSetKey + userId, tagId + ":" + albumId);
            // 互斥逻辑，仅点赞/点踩
            if (hasOpposite) {
                redisUtil.hincrBy(key, oppositeHashKey, -1);
                redisUtil.removeMember(oppositeSetKey + userId, tagId + ":" + albumId);
            }
        }
        TagStatusMessageDTO tagStatusMessageDTO = new TagStatusMessageDTO();
        tagStatusMessageDTO.setTagId(tagId);
        tagStatusMessageDTO.setAlbumId(albumId);
        // 数量发生修改，发异步消息 刷新满足条件的标签
        msgProducer.sendMsg(RabbitConfig.ACTION_EXCHANGE,RabbitConfig.ROUTING_TAG_STATUS,JSONUtil.toJsonStr(tagStatusMessageDTO));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addTag(Integer albumId, Integer tagId) {
        TagInfo tagInfo = getById(tagId);
        if (tagInfo == null) {
            // 没有该标签
            return false;
        }
        // 判断该专辑已有该标签 （不重复添加）
        LambdaQueryWrapper<ArAlbumTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArAlbumTag::getAlbumId, albumId);
        queryWrapper.eq(ArAlbumTag::getTagId, tagId);
        long count = albumTagsService.count(queryWrapper);
        if (count > 0) {
            // 已有该标签， 不进行添加 改为点赞
            changeTagStat(albumId,tagId,Constants.ACTION_GREAT);
            return true;
        }
        // 执行数据更新保存操作
        operationWorkCount(tagId,1,Constants.WORK_COUNT_ADD);
        ArAlbumTag arAlbumTag = new ArAlbumTag();
        arAlbumTag.setAlbumId(albumId);
        arAlbumTag.setTagId(tagId);
        arAlbumTag.setIsDefault(false);
        arAlbumTag.setStatus(Constants.TAG_LOW_ORIGINALITY);
        return albumTagsService.save(arAlbumTag);
    }

    @Override
    public Boolean operationWorkCount(Integer id, Integer num, String type) {
        UpdateWrapper<TagInfo> updateWrapper = new UpdateWrapper<>();
        if (Constants.WORK_COUNT_ADD.equals(type)){
            updateWrapper.setSql(StrUtil.format("num = num + {}", num));
        }
        if (Constants.WORK_COUNT_DELETE.equals(type)){
            updateWrapper.setSql(StrUtil.format("num = num - {}", num));
            updateWrapper.last(StrUtil.format(" and (num - {} >= 0)", num));
        }
        updateWrapper.eq("id",id);
        boolean update = update(updateWrapper);
        if (!update) {
            throw new AsmrException("更新标签数量失败，标签Id = "+ id);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveTag(TagInfo request) {
        return super.save(request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeTag(Integer id) {
        // 删除专辑-标签关联数据
        LambdaQueryWrapper<ArAlbumTag> arAlbumTagQueryWrapper = new LambdaQueryWrapper<>();
        arAlbumTagQueryWrapper.eq(ArAlbumTag::getTagId, id);
        long count = albumTagsService.count(arAlbumTagQueryWrapper);
        if (count > 0) {
            // 这个方法如果出错会抛异常
            albumTagsService.remove(arAlbumTagQueryWrapper);
        }
        return super.removeById(id);
    }


}
